package com.liang.service.impl;


import com.baomidou.mybatisplus.annotation.TableField;
import com.liang.Event.Events.ExcusePassEvent;
import com.liang.Event.Events.ExcuseUnPassEvent;
import com.liang.Event.PublishService;
import com.liang.mapper.ArmyandexcuseDAO;
import com.liang.mapper.ArmyxDAO;
import com.liang.mapper.UserzarmyxuDAO;
import com.liang.myWebSocketServer.WebSocketServer;
import com.liang.pojo.Armyandexcuse;
import com.liang.pojo.Armyx;
import com.liang.pojo.Excuse;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.liang.mapper.ExcuseDAO;
import javax.annotation.Resource;

import com.liang.pojo.dto.ExcuseDto;
import com.liang.utils.DateUtils;
import com.qiniu.util.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.liang.service.ExcuseService;
import org.springframework.transaction.annotation.Transactional;

/**
 *@作者:lsk
 *Service实现类
 *@Date:2023/10/22
*/
@Service
public class ExcuseServiceImpl  implements ExcuseService{


	@Value("excuseAplay")
	private String excuceAplayTitle;

	@Value("excuceDelete")
	private String excuceDeleteTitle;
	@Resource
	private ExcuseDAO excusedao;

	@Resource
	private ArmyxDAO armyxDAO;

	@Autowired
	private StringRedisTemplate redisTemplate;


	@Resource
	private ArmyandexcuseDAO armyandexcuseDAO;

	@Autowired
	private WebSocketServer webSocketServer;

	@Resource
	private UserzarmyxuDAO userzarmyxuDAO;

	@Resource
	PublishService publishService;


	/**
	根据Excuse_id查询
	*/
	public Object selectByExcuse_id(Long excuse_id){
		return excusedao.selectByExcuse_id(excuse_id);
	}


	/**
	根据Excuse_id更新
	*/
	public Integer updateByExcuse_id(Excuse demo){
		return excusedao.updateByExcuse_id( demo);
	}



	/**
	根据Excuse_id删除
	*/
	public Integer deleteByExcuse_id(Long excuse_id){
		return excusedao.deleteByExcuse_id(excuse_id);
	}





	/**
	 insert:(插入)
	*/
	public Object insert(Excuse demo){
		excusedao.insertlsk(demo);
		return demo;
	}



	/**
	 insertOrUpdate(插入或更新(根据主键或唯一索引更新，主键和唯一索引不会改变))
	*/
	public Integer insertOrUpdate(Excuse demo){
		return excusedao.insertOrUpdatelsk(demo);
	}



	/**
	 insertBath:(批量插入)
	*/
	public Integer insertBatch(List<Excuse> list){
		return excusedao.insertBatchlsk(list);
	}



	/**
	 insertOrUpdateBatch:(批量插入或更新)
	*/
	public Integer insertOrUpdateBatch(List<Excuse> list){
		return excusedao.insertOrUpdateBatchlsk(list);
	}



	/**
	 selectList:(根据参数查询集合)
	*/
	public List<Excuse> selectList(Map<String,Object> param){
		if(param.get("pageNum") != null){
			int start = Integer.parseInt(param.get("pageSize").toString()) * (Integer.parseInt(param.get("pageNum").toString()) - 1);
			param.put("pageNum",start);
		}
		return excusedao.selectListlsk(param);
	}



	/**
	 selectCount:(根据集合查询数量)
	*/
	public Long selectCount(Map<String,Object> param){
		return excusedao.selectCountlsk(param);
	}


	/**
	 * 自己写的代码
	 */

	/**
	 * 用于增加Excuse
	 * @param excuse
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean addExcuse(Excuse excuse) {
		//获取当前时间字符串
		String todayDateTime = DateUtils.getTodayDateTime();

		//设置create_time,change_time
		excuse.setCreate_time(todayDateTime);
		excuse.setChange_time(todayDateTime);

		//设置army_id
		//1.获取当前申请用户的user_id，用于查询上级的army_id
		Long user_id = excuse.getUser_id();
		//2.获取上级的army_id
	    Long army_id = armyxDAO.getArmyFatherId(user_id);
	    //3.设置army_id
		excuse.setArmy_id(army_id);

		//存储这个请假信息到数据库中。
		Integer bit = excusedao.insertlsk(excuse);
		if(bit>0) {
			//如果成功添加数据到redis中,存储他的excuse_id
			redisTemplate.opsForSet().add(excuceAplayTitle+army_id,excuse.getExcuse_id().toString());
//			redisTemplate.opsForList().leftPush(excuceAplayTitle+army_id,excuse.getExcuse_id().toString());
			//存储到数据库armyandexcuse中
			Armyandexcuse armyandexcuse = new Armyandexcuse();
			armyandexcuse.setArmy_id(army_id);
			armyandexcuse.setExcuse_id(excuse.getExcuse_id());
			armyandexcuse.setApprove_opinion(0);
			armyandexcuseDAO.insertlsk(armyandexcuse);
			return true;
		}
		else return  false;
	}

	/**
	 * 上级审批下级请假条
	 * @param excuseDto
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean approveExcuse(ExcuseDto excuseDto) {
		Boolean bit = false;
		if(excuseDto.getApproveExcuse_state()){
			//上级同意审批的操作
//			redisTemplate.opsForList().remove(excuceAplayTitle+excuseDto.getArmy_id(),1,excuseDto.getExcuse_id().toString());

			//1.设置armyandexcuse中的approve_opinion为通过审核状态
			Armyandexcuse armyandexcuse = new Armyandexcuse();
			armyandexcuse.setExcuse_id(excuseDto.getExcuse_id());
			armyandexcuse.setApprove_opinion(1); //1代表通过审核
			armyandexcuse.setArmy_id(excuseDto.getArmy_id());
			armyandexcuseDAO.updateByArmy_idAndExcuse_id(armyandexcuse);

			//2.查询该army是否army_father_id不为0，如果存在则将他的army_father_id赋值为这个excuse的army_id。
			Armyx armyx = armyxDAO.selectByArmy_id(excuseDto.getArmy_id());
			Long army_father_id = armyx.getArmy_father_id();

			//3.移除redis中该army接收到的请假申请的这个申请的xcuse_id
			redisTemplate.opsForSet().remove(excuceAplayTitle+excuseDto.getArmy_id(),excuseDto.getExcuse_id().toString());
			if(army_father_id == 0){
				//代表着他就是审核的最高级别，不需要再向上传递
				//3.1 修改excuse中的excuse_state为2，代表这这个假条通过审核
				excusedao.setExcuseState(excuseDto.getExcuse_id(),2);

				//这个步应该是用户点击销假按钮才进行
				//3.2 将这个假条信息存入为销假的redis信息中，由他的直接上级来确定该用户是否已经销假。
//				Long fatherId = armyxDAO.getArmyFatherId(excuseDto.getUser_id());
//				redisTemplate.opsForSet().add(excuceDeleteTitle+fatherId,excuseDto.getExcuse_id().toString());

				//3.3 发送ExcusePassEvent事件让listener完成websocket消息告诉该用户该请假条已经被批准
//				webSocketServer.sendOneMessage(excuseDto.getUser_id(),"你于"+excuseDto.getCreate_time()+"申请的假条被批准");
				publishService.pub(new ExcusePassEvent(excuseDto));
				//3.4.设置bit的值
				bit = true;
			}else{
				//4代表着他不是最上级领导需要把这个审批意见继续上传

				//4.1.修改excuse中的army_id为其现有army_id的上级领导id
				Excuse excuse = new Excuse();
				excuse.setExcuse_id(excuseDto.getExcuse_id());
				excuse.setArmy_id(army_father_id);
				excusedao.updateByExcuse_id(excuse);

				//4.2.增加数据到armyandexcuse
				Armyandexcuse armyandexcuse1 = new Armyandexcuse();
				armyandexcuse1.setArmy_id(army_father_id);
				armyandexcuse1.setExcuse_id(excuseDto.getExcuse_id());
				armyandexcuse1.setApprove_opinion(0);
				armyandexcuseDAO.insertlsk(armyandexcuse1);

//				4.3.增加数据到redis中，他的上级领导待批阅的请假申请的set中。
				redisTemplate.opsForSet().add(excuceAplayTitle+army_father_id,excuseDto.getExcuse_id().toString());

				//4.4.设置bit的值
				bit = true;
			}
		}else{
			//上级不同意审批的操作
			//1.设置数据库中excuse中的excuse_state为1代表没有通过审核
			excusedao.setExcuseState(excuseDto.getExcuse_id(),1);

			//2.设置armyandexcuse中的approve_opinion为未通过审核状态
			Armyandexcuse armyandexcuse = new Armyandexcuse();
			armyandexcuse.setExcuse_id(excuseDto.getExcuse_id());
			armyandexcuse.setApprove_opinion(2);  //2代表没有通过审核
			armyandexcuse.setArmy_id(excuseDto.getArmy_id());
			armyandexcuseDAO.updateByArmy_idAndExcuse_id(armyandexcuse);

			//3.发布ExcuseUnPassEvent让监听器websocket消息告诉这个用户请假未被批准.
//			webSocketServer.sendOneMessage(excuseDto.getUser_id(),"你于"+excuseDto.getCreate_time()+"申请的假条未被批准");
			publishService.pub(new ExcuseUnPassEvent(excuseDto));
			//4.移除redis中该army接收到的请假申请的这个申请的excuse_id
			redisTemplate.opsForSet().remove(excuceAplayTitle+excuseDto.getArmy_id(),excuseDto.getExcuse_id().toString());
			//5.设置返回值
			bit = true;
		}

		return  bit;
	}

	/**
	 * 用于用户的销假请求
	 * @param excuseid
	 * @return
	 */
	@Override
	public Boolean deleteExcuse(Long excuseid) {

		//1.设置excuse中flag为1，代表着销假正在审批中。
		Excuse excuse = new Excuse();
		excuse.setExcuse_id(excuseid);
		excuse.setFlag(1);
		//跟新数据的跟新事件，用于判断用户是否超时
		excuse.setChange_time(DateUtils.getTodayDateTime());

		excusedao.updateByExcuse_id(excuse);

		//2.将这个销假的信息存储到redis中，key为这个用户的直接上级，value为这个申请的excuseid
		//2.1.获取这个excuse的申请用户的直接上级的army_id
		Excuse excuse1 = excusedao.selectByExcuse_id(excuseid);
		Long user_id = excuse1.getUser_id();
		Long armyFatherId = armyxDAO.getArmyFatherId(user_id);

		//将这个销假的信息存储到redis中，key为这个用户的直接上级，value为这个申请的excuseid
		redisTemplate.opsForSet().add(excuceDeleteTitle+armyFatherId,excuseid.toString());

		return true;
	}

	/**
	 * 获取本单位用户请假条列表
	 * @param excuseDto
	 * @return
	 */
	@Override
	public Map approveExcuseList(ExcuseDto excuseDto) {
		HashMap<String, Object> map = new HashMap<>();

		//1.从redis中获取该部门所有的请假条id
		//1.1.获取该部门的army_id,user_id当前用户id
		Long user_id = excuseDto.getUser_id();
		Long army_id = userzarmyxuDAO.selectArmyIdbyUserId(user_id);
		Set<String> members = redisTemplate.opsForSet().members(excuceAplayTitle + army_id);

		//判断获取的members是否为空
		if(members.size() == 0){
			//2.为空操作，设置approveExcuseList为null，total为0
			map.put("approveExcuseList",null);
			map.put("total",0);
		}else{
			//3.不为空操作
			//3.1 将set转化为list[long]
			List<Long> list = members.stream().map((item) -> {
				return Long.parseLong(item);
			}).collect(Collectors.toList());

			//4.构建查询条件
			//4.1构建分页条件
//			Integer start = (excuseDto.getPageNum() - 1) *excuseDto.getPageSize();
//			Integer limit = excuseDto.getPageSize();
//			excuseDto.setStart(start);
//			excuseDto.setLimit(limit);

			//4.2.构建查询所用的map
			HashMap<String, Object> selectMap = new HashMap<>();

			selectMap.put("excuseDto",excuseDto);
			selectMap.put("ExcuseIdList",list);

			//4.3获取了该单位收到的用户的请假信息
		 	List<ExcuseDto>  approveExcuseList = excusedao.approveExcuseList(selectMap);

		 	//4.4.获取该条件下的总记录数目
			Integer total =  excusedao.approveExcuseListCounts(selectMap);

			//返回值map
			map.put("approveExcuseList",approveExcuseList);
			map.put("total",total);
		}
		return map;
	}

	/**
	 * 获取当前用户正在申请的请假条记录
	 * @param userid
	 * @return
	 */
	@Override
	public Map approvingExcuseList(Long userid) {

	List<ExcuseDto> list = excusedao.approvingExcuseList(userid);
	Integer total = excusedao.approvingExcuseListCounts(userid);
	HashMap<String, Object> map = new HashMap<>();
	map.put("list",list);
	map.put("total",total);
	return  map;
	}

	/**
	 * 获取该用户的申请历史
	 * @param excuseDto
	 * @return
	 */
	@Override
	public Map approvedExcuseList(ExcuseDto excuseDto) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		HashMap<String, Object> map = new HashMap<>();
		//获取用户的请假条历史，指的是查找用户已经销假的请求。即flag=2 的记录
		//可以根据申请时间范围查询，excuse_state状态查询，1为没有通过审核，2为通过了审核，还可以根据该请假条是否超时，
		List<ExcuseDto> approvedExcuseList =  excusedao.approvedExcuseList(excuseDto);
		if(approvedExcuseList.size()!=0){
			approvedExcuseList.stream().forEach((item)->{

				String change_time = item.getChange_time();
				String end_time = item.getEnd_time();
				Date date1 = null;
				try {
					date1 = simpleDateFormat.parse(change_time);
					Date date2 = simpleDateFormat.parse(end_time);
					int i = date1.compareTo(date2);
					if (i <= 0) {
						item.setBit(1);
						item.setShowbit("未超时");
					}
					else  {
						item.setBit(2);
						item.setShowbit("超时");
					}
				} catch (ParseException e) {
					e.printStackTrace();
				}

//				Date date1 = new Date(change_time);
//				Date date2 = new Date(end_time);
			});
			if(excuseDto.getBit() !=null){
				List<ExcuseDto> collect = approvedExcuseList.stream().filter((item) -> {
					return item.getBit() == excuseDto.getBit();
				}).collect(Collectors.toList());
				map.put("approvedExcuseList",collect);
				map.put("total",collect.size());
				return map;
			}
		}
		//构造返回的map对象
		map.put("approvedExcuseList",approvedExcuseList);
		map.put("total",approvedExcuseList.size());
		return map;
	}

	/**
	 * 获取本单位正在申请销假的列表
	 * @param excuseDto
	 * @return
	 */
	@Override
	public Map getDeletingExcuseList(ExcuseDto excuseDto) {
		//构建返回值
		HashMap<String, Object> map = new HashMap<>();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//根据当前用户的userid查询出他的army_id;
		Long army_id = userzarmyxuDAO.selectArmyIdbyUserId(excuseDto.getUser_id());

		//根据army_id在redis中查询出本单位申请销假的excuse_id；
		Set<String> excuseids = redisTemplate.opsForSet().members(excuceDeleteTitle + army_id);
		//如果该单位没有审批的请求销假的请求
		if(excuseids.size() == 0){
			map.put("DeletingExcuseList",null);
			map.put("total",0);
		}else {
			//将String类型转化为long类型
			List<Long> collect = excuseids.stream().map(excuseid -> {
				return Long.parseLong(excuseid);
			}).collect(Collectors.toList());

			//构建查询条件
			HashMap<String, Object> selectContmap = new HashMap<>();
			selectContmap.put("list", collect);
			selectContmap.put("excuseDto", excuseDto);
			List<ExcuseDto> list = excusedao.getDeletingExcuseList(selectContmap);

			//构建是否超时的bit
			if (list.size() != 0) {
				list.stream().forEach(item -> {
					String change_time = item.getChange_time();
					String end_time = item.getEnd_time();
					Date date1 = null;
					try {
						date1 = simpleDateFormat.parse(change_time);
						Date date2 = simpleDateFormat.parse(end_time);
						int i = date1.compareTo(date2);
						if (i <= 0) item.setBit(1);
						else  item.setBit(2);
					} catch (ParseException e) {
						e.printStackTrace();
					}
				});
				//还要进行过滤
				if(excuseDto.getBit() !=null){
						list.stream().filter(item->item.getBit() == excuseDto.getBit());
				}
			}
			map.put("DeletingExcuseList",list);
			map.put("total",list.size());

		}

		return map;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Boolean superiorDeleteExcuse(ExcuseDto excuseDto) {
		//修改数据库中假条信息,修改excuse中的flag状态为2代表已经销假
		Excuse excuse = new Excuse();
		excuse.setExcuse_id(excuseDto.getExcuse_id());
		excuse.setFlag(2);
		Integer integer = excusedao.updateByExcuse_id(excuse);

		//删除redis中本单位存储的销假用户信息
		if(integer != null){
			redisTemplate.opsForSet().remove(excuceDeleteTitle+excuseDto.getArmy_id(),excuseDto.getExcuse_id().toString());
		}
		return true;
	}

	/**
	 * 获取用户还没有销假的请求
	 * @param excuseDto
	 * @return
	 */
	@Override
	public Map willDeleteExcuse(ExcuseDto excuseDto) {
		HashMap<String, Object> map = new HashMap<>();
		//判断excuse_state为2，且flag为0的sql
		//动态查询，根据范围查询申请时间，根据请假内容模糊查询reason，根据请假条是否开始，是否超时，是否正在进行
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		List<ExcuseDto>  willDeleteExcuseList =	 excusedao.willDeleteExcuse(excuseDto);

		if(willDeleteExcuseList.size() ==0){
			map.put("willDeleteExcuseList",willDeleteExcuseList);
			map.put("total",0);
			return map;
		}
		//循环设置bit的值
		willDeleteExcuseList.stream().forEach(item->{
			String start_time = item.getStart_time();
			String end_time = item.getEnd_time();
//			Date endtime = new Date(end_time);
			Date nowdate = new Date();
			Date starttime = null;
			try {
				starttime = simpleDateFormat.parse(start_time);
				Date endtime = simpleDateFormat.parse(end_time);
				int i = starttime.compareTo(nowdate);
				if(i>0){
					item.setBit(3);
					item.setShowbit("未开始");
				}else{
					int j = endtime.compareTo(nowdate);
					if(j>0){
						item.setBit(1);
						item.setShowbit("未超时");
					}
					else{
						item.setBit(2);
						item.setShowbit("超时");
					}
				}
			} catch (ParseException e) {
				e.printStackTrace();
			}

			if(item.getFlag() ==0&& item.getExcuse_state() == 2){
				item.setIsDeleteExcuse(true);
			}
		});
		//条件判断查询条件bit的条件
		if(excuseDto.getBit()!=null){
			willDeleteExcuseList.stream().filter(item->item.getBit() == excuseDto.getBit());
		}

		//构建返回值
		map.put("willDeleteExcuseList",willDeleteExcuseList);
		map.put("total",willDeleteExcuseList.size());
		return map;
	}


}